home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / hdf / docs / hdfvset.lha / HDFVset.ch2 < prev    next >
Text File  |  1994-01-10  |  17KB  |  510 lines

  1. 2.1    NCSA HDF Vset
  2.  
  3.  
  4. Vdatas    2.1
  5.  
  6.  
  7. National Center for Supercomputing Applications
  8.  
  9. November 1990
  10.  
  11.                                                                 
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  
  19.  
  20.  
  21. Chapter 2    Vdatas
  22.  
  23.  
  24.  
  25. Chapter Overview
  26. Interlacing
  27. Working with Interlacing
  28. HDF Data Format
  29. Vdata Options
  30. Selecting Random-Access Reads
  31. Writing Fields of Mixed Types
  32. Specifying Read Fields
  33. Inquiring About a Vdata
  34. Using Searching Strategies
  35. Accessing Vdatas Simultaneously
  36.  
  37. Chapter Overview
  38.  
  39. This section points out some properties of vdatas that might not be 
  40. obvious from earlier examples. The section covers important 
  41. concepts and ideas on which the HDF Vset is based. It also gives a 
  42. better idea of how the vdata's properties and various routines may 
  43. be used to gain greater control over data organization and access. 
  44.  
  45.  
  46. Interlacing
  47.  
  48. Data for all the fields with a vdata are stored according to a 
  49. non-interlaced or fully-interlaced scheme. The concept of 
  50. interlacing is simple but important╤it describes how data of one 
  51. field is related to data of another in a storage area (whether in 
  52. memory or in a vdata in the file). Note that interlacing applies 
  53. only to fields.
  54.  
  55. In a non-interlaced scheme, all data values for one field are stored 
  56. together contiguously. Think of all the data values for one field 
  57. forming one data chunk, and all the data values for another field 
  58. forming another chunk. Such an interlace scheme emphasizes 
  59. keeping all data values for one field close together. Figure 2.1a 
  60. shows a vdata with non-interlaced fields.
  61.  
  62. In a fully-interlaced scheme, all data values for one field are 
  63. never located contiguously. Each data value of one field is 
  64. immediately followed by one data value of another field, until a 
  65. data value is taken for all fields. In other words, data values from 
  66. different fields are intertwined together as aggregates, where each 
  67. aggregate comprises exactly one data value from each of the fields. 
  68. Such an interlace scheme emphasizes keeping related data values 
  69. from different fields together. Figure 2.1b shows a vdata with 
  70. fully-interlaced fields.
  71.  
  72. When talking about interlacing, a distinction is made between 
  73. when data is in memory and when data resides in a vdata in a 
  74. file. The layout of data in memory is its buffer interlace, whereas 
  75. the layout of data within a vdata in the file is the vdata's 
  76. file interlace.
  77.  
  78.  
  79. Working with Interlacing 
  80.  
  81. Data as it appears in the file may or may not have the same 
  82. interlace as the data appears in memory. This feature allows 
  83. applications to extract data interlaced in the manner most useful to 
  84. it, independent of the file interlace. In the same way, data may be 
  85. stored in the file with an interlace different from how it appears in 
  86. memory.
  87.  
  88. The HDF Vset interface always requires that the buffer interlace 
  89. be specified in any data transfer. However, it does not require the 
  90. file interlace be specified. By default, this buffer interlace is 
  91. always set to FULL_INTERLACE for every newly created vdata. 
  92. Thus, fields in a vdata are always fully-interlaced by default. You 
  93. may change the interlace for any particular vdata to 
  94. NO_INTERLACE with the routine VSsetinterlace. Vdatas within 
  95. an HDF file may be set to different file interlaces if so desired. 
  96. However, note that the file interlace of existing vdatas cannot be 
  97. changed.
  98.  
  99. The buffer interlace must be specified when reading or writing 
  100. data. Both the read/write routines, Vsread and VSwrite, require 
  101. the buffer interlace to be specified as the fourth argument. When 
  102. reading data, the buffer interlace tells the read routine how the 
  103. returned data should be interlaced in the read buffer. When 
  104. writing data, the buffer interlace informs the write routine how 
  105. data in the write buffer is interlaced.
  106.  
  107. Finally, note that when only one field is read or written, or when 
  108. there is only one field in a vdata or in memory, interlacing is not 
  109. relevant. In such cases, specifying FULL_INTERLACE or 
  110. NO_INTERLACE yields identical results.
  111.  
  112. Figure 2.1    Interlacing Within 
  113. Vdatas
  114.  
  115.                                                          
  116.  
  117.  
  118. HDF Data Format
  119.  
  120. Data stored in a vdata is in IEEE 32-bit floating-point format. 
  121. When data is read or written, the calling interface always convert 
  122. from IEEE format to the correct data format and byte length for that 
  123. particular machine, and vice versa. For instance, 4-byte floats 
  124. created on a VMS machine are stored as 4-byte IEEE floats in the 
  125. vset in the HDF file. Later when a Cray (running UNICOS) reads 
  126. the data, the 4-byte float value is converted to an 8-byte Cray float 
  127. value. 
  128.  
  129. The data stored within a vdata is always contiguous; i.e., the vdata 
  130. does not contain any non-data spaces or holes. This is true for both 
  131. fully-interlaced and non-interlaced data. Consequently, any call 
  132. to VSread always returns data that is contiguous, and any call to 
  133. VSwrite expects data to be contiguous.
  134.  
  135.  
  136. Vdata Options 
  137.  
  138. Selecting Random-Access 
  139. Reads 
  140. The access routine VSseek is used together with a VSread to affect a 
  141. random-access read within a vdata. VSseek requires an 
  142. argument that specifies the element location within that vdata. 
  143. This value will be an integer, with 0 for the first element position, 1 
  144. as the second element position, etc. 
  145.  
  146. Thus, the following code segment seeks to the 51st element in the 
  147. vdata vs, and then reads data for four elements according to the 
  148. fields specified by the last VSsetfields call:
  149.  
  150.     VSseek(vs,50);
  151.     VSread(vs,buf,4,interlace);
  152.  
  153.  
  154. Writing Fields of Mixed 
  155. Types
  156. The fields within one vdata need not all be of the same type. You 
  157. may store fields of integer, float, and character types together 
  158. within one vdata.
  159.  
  160. Assume that the fields "F1", "F2", "I1" and "C1" represent data 
  161. fields of float, float, character, and integer types of order 1, 
  162. respectively. The code segment below first defines these fields, 
  163. and then specifies that the data from buffer buf be written 
  164. contiguously into the vdata vs according to the format 
  165. "F1,I1,F2,C1".
  166.  
  167.     ...
  168.     VSfdefine (vs, ╥F1╙, LOCAL_FLOATTYPE, 1);
  169.     VSfdefine (vs, ╥I1╙, LOCAL_INTTYPE, 1);
  170.     VSfdefine (vs, ╥F2╙, LOCAL_FLOATTYPE, 1);
  171.     VSfdefine (vs, ╥C1╙, LOCAL_CHARTYPE, 1);
  172.     VSsetfields(vs,"F1,I1,F2,C1 ");
  173.     VSwrite(vs,buf,nvertices,interlace);
  174.  
  175.  
  176. The data in buf must also be contiguous. There must be no padding 
  177. or alignment, or non-data spaces. 
  178.  
  179. Storing mixed field types within a vdata is very efficient, and is 
  180. useful to applications that use structures. Such usage intuitively 
  181. associates a structure in memory to a vdata in the file. However, in 
  182. general, structures contain padding or alignment bytes (Figure 
  183. 2.2) and as such, may not be directly written out into a vdata with a 
  184. VSwrite call. The data from such a structure must first be packed 
  185. into an array so that the array does not contain holes or non-data 
  186. spaces. This packed array may then be written out into one vdata 
  187. using VSwrite.
  188.  
  189.  
  190. Figure 2.2    Structure Array Vs. Packed Array
  191.  
  192.                                                                   
  193.  
  194.  
  195.  
  196. The following code segment (Figure 2.3) illustrates packing data 
  197. in the fields from a structure array ss into a contiguous array pp, 
  198. and then writing the array pp into a vdata.
  199.  
  200. Figure 2.3    Packing Data
  201.  
  202. #define NVERTICES 500
  203. main() {
  204.  
  205.     struct {   
  206.         float F1;
  207.         int I1;
  208.         float F2; 
  209.         char C1; 
  210.     }   ss[NVERTICES];
  211.  
  212.     unsigned char *pp, *p;
  213.     int i;
  214.  
  215.     ...
  216.     pp = (unsigned char*)  malloc(  NVERTICES* (2*sizeof(float) + sizeof(char) +     
  217.                             sizeof(int))   );
  218.     p = pp;
  219.     for(i=0;i<NVERTICES ;i++) {
  220.         movebytes (p,  &ss[i].F1, sizeof(float) );    p+=sizeof(float);
  221.         movebytes (p,  &ss[i].I1, sizeof(int) );    p+=sizeof(int);
  222.         movebytes (p,  &ss[i].F2, sizeof(float) );    p+=sizeof(float);   
  223.         movebytes (p,  &ss[i].C1, sizeof(char) );    p+=sizeof(char);
  224.         }
  225.  
  226.     VSsetfields(vs,"F1,I1,F2,C1");
  227.     VSwrite(vs,pp,NVERTICES, FULL_INTERLACE);
  228.     ...
  229.  
  230.     } /* main */
  231.  
  232. movebytes(dest, src, nbytes) unsigned char *dest, *src; int nbytes; {
  233.     int i;
  234.        for(i=0;i<nbytes;i++) *dest++ = *src++:
  235.      }
  236.  
  237.  
  238. Note the following points:
  239.  
  240. 1.    The exact amount of memory is allocated (i.e., NVERTICES 
  241. times the size of 2 floats, 1 char and 1 integer).
  242.  
  243. 2.    The routine movebytes is called for each field in the sequence 
  244. desired (i.e., "F1,I1,F2,C1"). The movebytes routine may be 
  245. replaced by any efficient   routine.
  246.  
  247. 3.    Data in one structure record is packed each time the code moves 
  248. through the loop.
  249.  
  250. 4.    The contiguous data in array pp may now be stored with by 
  251. VSwrite.
  252.  
  253.  
  254. Specifying Read Fields
  255. The data read from a vdata depends only on the fields specified by 
  256. the VSsetfields call. Thus, for reading, you can select one or 
  257. more fields from the vdata. 
  258.  
  259. For example, assume that the vdata vs contains fields specified by 
  260. "AFLOAT, BFLOAT, CCHAR, DINT, EINT, FCHAR" and is stored in 
  261. that sequence. (The type of each field is suggested by the 
  262. fieldname.) Each of the following VSsetfields calls is valid 
  263. before a VSread call:
  264.  
  265.     VSsetfields(vs,"BFLOAT");    
  266.     VSsetfields(vs,"BFLOAT,AFLOAT");
  267.     VSsetfields(vs,"EINT,AFLOAT");
  268.     VSsetfields(vs,"CCHAR,DINT,FCHAR");
  269.     VSsetfields(vs," FCHAR, EINT, DINT, CCHAR,BFLOAT, AFLOAT")
  270.  
  271.  
  272. The last call specifies all fields be read in reverse sequence.
  273.  
  274. Note that  the VSread call always returns contiguous data for the 
  275. fields specified. Furthermore, the data is returned in the sequence 
  276. specified. 
  277.  
  278. Several calls to VSsetfield and VSread may follow one another to 
  279. read data from the same vdata. However, note that the read 
  280. operations are sequential. Thus, in the following code segment, the 
  281. first VSread returns 10 "AFLOAT" data values from the first 10 
  282. elements in the vdata, while the second VSread returns 10 
  283. "BFLOAT" data values  from the second 10 elements (i.e., 11-20) in 
  284. the vdata.
  285.  
  286.     VSsetfields(vs,"AFLOAT");
  287.     VSread(vs,buf1,10, interlace);
  288.  
  289.     VSsetfields(vs,"BFLOAT");
  290.     VSread(vs,buf2,10, interlace);
  291.  
  292.  
  293. To actually read the first 10 "BFLOAT" data values, the access 
  294. routine VSseek must be explicitly called to position the read pointer 
  295. back to the first element positions. The following code segment 
  296. correctly reads the first 10 "AFLOAT" and "BFLOAT" values into two 
  297. separate float arrays buf1 and buf2.
  298.  
  299.     VSsetfields(vs,"AFLOAT");
  300.     VSread(vs,buf1,10, interlace);
  301.  
  302.     VSseek(vs,0);    /*seeks to first element /
  303.     VSsetfields(vs,"BFLOAT");
  304.     VSread(vs,buf2,10, interlace);
  305.  
  306.  
  307. Inquiring About a Vdata
  308. The inquire routine VSinquire is the general inquiry routine for 
  309. requesting information about the contents of a vdata. It returns the 
  310. number of elements in the vdata; the interlace, a string containing 
  311. (comma-separated) names of the fields in the vdata; the byte size of 
  312. a element in the vdata; and the name of the vdata itself, if any.
  313.  
  314. This routine is useful when searching through the HDF file for a 
  315. particular vdata by name or by fieldname. 
  316.  
  317.  
  318. Using Searching Strategies 
  319. Applications that allow users to specify which vgroup or vdata to 
  320. access should contain general search strategies. The most general 
  321. search strategy searches by the name of a vgroup or vdata. The 
  322. names of vgroups and vdatas are the best means for the user to 
  323. identify them by, since names are readable and mnemonic as 
  324. compared to integer identifiers (ids) of vgroups and vdatas).
  325.  
  326.  
  327. Searching for a Vgroup by Name
  328. Locating a vgroup by name is simple. It merely involves 
  329. searching through all vgroups in the file, and then inquiring for 
  330. the name of the vgroup. The search routine Vgetid sequences 
  331. through the file and returns the vgids of the vgroups one at a time, 
  332. or returns -1 when no more vgids are found. The code in Figure 
  333. 2.4 illustrates the search for a vgroup named "transistor P╙.
  334.  
  335. Figure 2.4    Searching for a Vgroup
  336.  
  337.     char vsname[50];
  338.     VGROUP *vg;
  339.     int  vgid;
  340.     ...
  341.     vgid = -1;  
  342.     found = 0;
  343.     while( (vgid = Vgetid(f, vgid)) != -1) {
  344.         vg = (VGROUP*) Vattach(f,vgid,"r");
  345.         Vinquire(vs,&nentries, vgname);
  346.         if (!strcpy(vsname,"transistor P"))   {   found = 1; break; }
  347.                 else  VSdetach(vs);
  348.         }
  349.     if (! found) { printf("vgroup 'transistor P' not found");  return;  }
  350.     ...
  351.  
  352.  
  353.  
  354. Searching for a Vdata by Name
  355. Similar code is used for searching for a specific vdata by name. 
  356. The code in Figure 2.5 looks for the vdata named "transistor P 
  357. voltages";  Here, the routines VSinquire and VSgetid are used 
  358. instead of Vinquire and Vgetid.
  359.  
  360. Figure 2.5    Searching for a Vdata
  361.  
  362.     char vgname[50];
  363.     VDATA *vs;
  364.     int  vsid;
  365.     ...
  366.     vsid = -1;
  367.     found = 0;
  368.     while( (vsid = VSgetid(f, vsid)) != -1) {
  369.         vs = (VDATA*) VSattach(f,vsid,"r");
  370.         VSinquire(vs,&nvertices, &interlace, fields, &vsize, vsname);
  371.         if (!strcpy(vsname,"transistor P voltages")) {  found = 1; break;   }
  372.                 else  VSdetach(vs);
  373.         }
  374.     if (! found) { printf("vdata 'transistor P' not found");  return;  }
  375.     ...
  376.  
  377. Hierarchical Search for a Vdata by Name
  378. A more systematic way of searching for a vdata takes into account 
  379. the hierarchical nature of the vset. Thus, you would first go through 
  380. all vgroups and examine each entry in the vgroup. Each entry is 
  381. either a vgroup or a vdata identifier. If it is a vdata identifier, just 
  382. inquire for its name. However, if it is a vgroup identifier, all the 
  383. entries in that vgroup need to be searched in a similar manner. 
  384.  
  385. The code in Figure 2.6 looks for the vdata named "pressure  
  386. site#9". The search routine Vgetid is used to locate all the 
  387. vgroups one by one, while the search routine VSgetnext is used to 
  388. locate the identifiers of all the entities in a vgroup. Finally, the 
  389. inquiry routines Visvg and Visvs each test whether an identifier 
  390. in a vgroup is a vgroup or vdata.
  391.  
  392. Figure 2.6    Hierarchical Searching
  393.  
  394.  
  395.     VGROUP *vg;
  396.     VDATA  *vs;
  397.     int vgid, vsid,id;
  398.     ...
  399.     found = 0;
  400.     vgid = -1;
  401.     while( (vgid = Vgetid(f, vgid)) != -1) {
  402.         vg = (VGROUP*) Vattach(f,vgid,"r");
  403.         id = -1;
  404.         while((id = Vgetnext(vg, id)) != -1) {
  405.                 if      (Visvs(vg,id) ) {    /*  vdata id */
  406.                 vs =  (VDATA*) VSattach(f,id,"r");
  407.                 VSinquire(vs,&nvertices, &interlace, fields, &vsize, vsname);
  408.                 if  (!strcpy(vsname,"pressure site#9")) { found=1; break; }
  409.                                      else  VSdetach(vs);
  410.                  }
  411.               else (Visvg(vg,id) ) {      /* vgroup id */
  412.                 ...                 /* perform similar  search on vgroup vg */
  413.                    }
  414.               }
  415.         if (found) break;
  416.         Vdetach(vg);
  417.         } 
  418.     if(!found) { printf("vdata 'pressure site#9' not found");  return; }
  419.     ...
  420.  
  421.  
  422. Searching for a Vdata by Fieldname
  423. Finally, to search for a vdata by specifying only the fieldnames, 
  424. use the inquiry routine VSfexist. This routine takes a vdata 
  425. pointer as an argument, and returns true if all the specified fields 
  426. exist in that vdata. In the following code segment (Figure 2.7), all 
  427. vdatas in the file are searched through until the first vdata to 
  428. contain the fields "PZ, PX" is found.
  429.  
  430. Figure 2.7    Search Using Fieldnames
  431.  
  432.  
  433.     VDATA *vs;
  434.     int  vsid;
  435.     ...
  436.     vsid = -1;  
  437.     found = 0;
  438.     while( (vsid = VSgetid(f, vsid)) != -1) {
  439.         vs= (VDATA*) VSattach(f,vsid,"r");
  440.         if( VSfexist(vs,"PZ,PX")) { found = 1; break; }
  441.         else VSdetach(vs);
  442.         }
  443.     if (! found) { printf("fields 'PZ,PX' not found in any vdata");  return;  }
  444.     ...
  445.  
  446.  
  447.  
  448. Note that VSfexist returns true only if all the specified fields, in 
  449. any order, exist in the vdata. For instance, specifying "PZ,PX" or  
  450. "PX,PZ"  in the call to VSfexist will return true for a vdata that 
  451. contains the fields "PX,PY,PZ". 
  452.  
  453.  
  454. Accessing Vdatas 
  455. Simultaneously 
  456. Several vdatas may be attached for simultaneous access. This is 
  457. analogous to having several files opened at the same time. 
  458.  
  459.  
  460. Reading Data
  461. Reading data from several vdatas at the same time is efficient and 
  462. easy, as the code segment in Figure 2.8 shows.
  463.  
  464. Figure 2.8    Accessing Vdatas 
  465. Simultaneously
  466.     float xval, yval;
  467.      v1 = (VDATA*)VSattach(f,vsid1,"r");
  468.      v2 = (VDATA*)VSattach(f,vsid2,"r");
  469.  
  470.     VSsetfields(v1,"PX");
  471.     VSsetfields(v2,"DENSITY");
  472.  
  473.     for(i=0;i<1000;i++) {
  474.         VSread(v1,&xval,1,FULL_INTERLACE);
  475.         VSread(v2,&yval,1,FULL_INTERLACE);
  476.         plot_point (xval,yval);
  477.         }
  478.     ...
  479.     VSdetach(v1);
  480.     VSdetach(v2);
  481.  
  482.  
  483. Note the following points about the above code:
  484.  
  485. 1.    Two vdatas v1 and v2 are opened simultaneously.
  486.  
  487. 2.    The VSread from v1 returns one "PX" value in xval, while the 
  488. VSread from v2 returns one "DENSITY" value in yval.
  489.  
  490. 3.    A plotting routine, plot_point, processes each pair of data in 
  491. xval and yval.
  492. Writing Data
  493. Writing data to several vdatas in the same file simultaneously is 
  494. supported, but can be inefficient since each vgroup and each vdata 
  495. is always maintained as a contiguous data block in the file.
  496.  
  497. As an example, assume that two vdatas, A and B, exist in an HDF 
  498. file such that B immediately follows A in the file. When new data 
  499. is to be written out (appended) to A, the file storage for A has to be 
  500. expanded; however, this cannot be done since B immediately 
  501. follows A. Thus, A must be copied to the end of the file, and only 
  502. then can new data be appended to it. This procedure creates an area 
  503. of useless space in the file where the original vdata A was located. 
  504. As a result, file space becomes fragmented and the file grows 
  505. unnecessarily large.
  506.  
  507. As a rule, when writing data out to several vdatas, it is more 
  508. efficient to completely write out data for one vdata  before 
  509. proceeding to write data for the next vdata.
  510.